package com.buobao.screenlogcat

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.delay
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield

fun main() {
    //函数传参
//    callfun {
//        println("this is call function! $it")
//    }

    //runBlocking可以创建协程作用域，但是会阻塞主线程，在其中创建的所有协程执行完后，主线程才会继续执行
//    runBlocking {
//        //这里可以通过launc或者async创建协程，区别是launch会返回一个Job，可以对Job进行操作，而async则会返回一个Deferred，可以对Deferred进行操作
//        launch {
//            suspendFun("this is coroutine1",500)
//        }
//        launch {
//            suspendFun("this is coroutine2",1500)
//        }
//        launch {
//            suspendFun("this is coroutine3",200)
//        }
//    }
//    println("this is main thread")


    //通过使用GlobalScope创建协程，协程会自动加入到协程调度器中，协程调度器默认是主线程
    //这里主线程会继续执行，而不是等待两个协程执行完，
    //当主线程执行完后就看不到两个协程的执行结果了
    //所以需要编码等待两个协程执行完
//    GlobalScope.launch {
//        launch {
//            suspendFun("this is coroutine1", 0)
//        }
//
//        launch {
//            suspendFun("this is coroutine2", 1500)
//        }
//    }
//
//    println("this is main thread")

    //构造函数中创建的job是用来取消协程作用域的，其调用的cancel其实就是job的cancel，除此之外还指定了默认的写成调度器
//    val coroutineScope = CoroutineScope(Job()+Dispatchers.IO)
//
//    coroutineScope.launch {
//        val job1 = coroutineScope.launch {
//            suspendFun("this is coroutine1", 0)
//        }
//        val job2 = coroutineScope.launch {
//            suspendFun("this is coroutine2", 1500)
//        }
//        job1.join()
//        job2.join()
//    }
//    //取消协程作用域，协程调度器会自动取消所有加入到协程调度器中的协程
//    coroutineScope.cancel()

    //协程作用域下的协程执行失败时会取消整个协程作用域下的写成，为了避免这个问题可以采用以下方式定义协程作用域
//    val coroutineScope = CoroutineScope(SupervisorJob()+Dispatchers.Default)

    //在协程作用域中调整调度器可以通过launch async withcontext等方式
//    coroutineScope.launch {
//        launch(Dispatchers.Main) {
//            suspendFun("this is coroutine1", 0)
//        }
//        async(Dispatchers.IO) {
//            suspendFun("this is coroutine2", 1500)
//        }
//        println("-------")
//        withContext(Dispatchers.Main) {
//            suspendFun("this is coroutine3", 200)
//        }
//    }

    //除此之外在android中有很多预定于的协程作用域，他们已经绑定了相应组件的生命周期可以直接使用
    //viewModelScope lifecycleScope 等等


//    runBlocking {
//        val job = launch {
//            suspendFun("this is coroutine1", 1500)
//        }
//        suspendFun("this is coroutine2", 0)
//        job.join()
//        println("end");
//    }


//    runBlocking {
//        launch {
//            yield() //放弃一次运行的机会
//            suspendFun("this is first launch",0)
//        }
//        launch {
//            suspendFun("this is second launch",0)
//        }
//    }


    runBlocking {
        val deferred1 = async {
            delay(2500)
            println("run first async")
            100
        }

        val deferred2=async {
            delay(500)
            println("run second async")
            200
        }

        val result = deferred1.await() + deferred2.await()
        println("result:$result")
    }
}


fun callfun(function: (time: Int) -> Unit) {
    function.invoke(100)
    function(20)
}

suspend fun suspendFun(msg: String, delay: Long) {
    delay(delay)
    println(msg)
}